#ifndef __IM_STREAM_H__
#define __IM_STREAM_H__

#include <im_base_types.h>
#include <im_object.h>
#include <im_io_channel.h>

/**
 * @defgroup IMStream
 * @ingroup PrivateIMBusIME
 * @{
 */

/** @struct IMStream
 *  @brief It's an interface class for real stream implementation.
 *
 *  The purpose of IMStream is serialization and deserialization of
 *  various types of data and objects.
 */

IM_BEGIN_DECLS

#define IM_STREAM(p)             (IM_TYPE_INSTANCE_CHECK_CAST((p),IM_TYPE_STREAM,IMStream))
#define IM_CONST_STREAM(p)       (IM_TYPE_INSTANCE_CHECK_CAST_CONST((p),IM_TYPE_STREAM,IMStream))
#define IM_STREAM_CLASS(c)       (IM_TYPE_CLASS_CHECK_CAST((c),IM_TYPE_STREAM,IMStreamClass))
#define IM_IS_STREAM(p)          (IM_TYPE_INSTANCE_CHECK_TYPE((p),IM_TYPE_STREAM))
#define IM_IS_STREAM_CLASS(c)    (IM_TYPE_CLASS_CHECK_TYPE((c),IM_TYPE_STREAM))
#define IM_STREAM_GET_CLASS(p)   (IM_TYPE_INSTANCE_GET_CLASS_CAST((p),IM_TYPE_STREAM,IMStreamClass))

typedef struct _IMStream         IMStream;
typedef struct _IMStreamClass    IMStreamClass;

struct _IMStream
{
    IMObject object;
};

struct _IMStreamClass
{
    IMObjectClass parent_class;

    IMBool      (*put_void)                 (IMStream           *stream);
    IMBool      (*put_char)                 (IMStream           *stream,
                                             IMChar              v_char);
    IMBool      (*put_uchar)                (IMStream           *stream,
                                             IMUChar             v_uchar);
    IMBool      (*put_bool)                 (IMStream           *stream,
                                             IMBool              v_bool);
    IMBool      (*put_int16)                (IMStream           *stream,
                                             IMInt16             v_int16);
    IMBool      (*put_uint16)               (IMStream           *stream,
                                             IMUInt16            v_uint16);
    IMBool      (*put_int32)                (IMStream           *stream,
                                             IMInt32             v_int32);
    IMBool      (*put_uint32)               (IMStream           *stream,
                                             IMUInt32            v_uint32);
    IMBool      (*put_int64)                (IMStream           *stream,
                                             IMInt64             v_int64);
    IMBool      (*put_uint64)               (IMStream           *stream,
                                             IMUInt64            v_uint64);
    IMBool      (*put_double)               (IMStream           *stream,
                                             IMDouble            v_double);
    IMBool      (*put_c_string)             (IMStream           *stream,
                                             const IMChar       *v_string,
                                             IMSize              v_strlen);
    IMBool      (*put_byte_array)           (IMStream           *stream,
                                             const IMPointer     v_array,
                                             IMSize              v_size);
    IMBool      (*put_bool_array)           (IMStream           *stream,
                                             const IMBool       *v_array,
                                             IMSize              v_size);
    IMBool      (*put_int16_array)          (IMStream           *stream,
                                             const IMInt16      *v_array,
                                             IMSize              v_size);
    IMBool      (*put_uint16_array)         (IMStream           *stream,
                                             const IMUInt16     *v_array,
                                             IMSize              v_size);
    IMBool      (*put_int32_array)          (IMStream           *stream,
                                             const IMInt32      *v_array,
                                             IMSize              v_size);
    IMBool      (*put_uint32_array)         (IMStream           *stream,
                                             const IMUInt32     *v_array,
                                             IMSize              v_size);
    IMBool      (*put_int64_array)          (IMStream           *stream,
                                             const IMInt64      *v_array,
                                             IMSize              v_size);
    IMBool      (*put_uint64_array)         (IMStream           *stream,
                                             const IMUInt64     *v_array,
                                             IMSize              v_size);
    IMBool      (*put_double_array)         (IMStream           *stream,
                                             const IMDouble     *v_array,
                                             IMSize              v_size);
    IMBool      (*put_object)               (IMStream           *stream,
                                             IMConstPointer      v_object);
    void        (*clear)                    (IMStream           *stream);

    IMType      (*get_data_type)            (IMStream           *stream);
    IMSize      (*get_data_size)            (IMStream           *stream);
    IMBool      (*get_void)                 (IMStream           *stream);
    IMBool      (*get_char)                 (IMStream           *stream,
                                             IMChar             *v_char);
    IMBool      (*get_uchar)                (IMStream           *stream,
                                             IMUChar            *v_uchar);
    IMBool      (*get_bool)                 (IMStream           *stream,
                                             IMBool             *v_bool);
    IMBool      (*get_int16)                (IMStream           *stream,
                                             IMInt16            *v_int16);
    IMBool      (*get_uint16)               (IMStream           *stream,
                                             IMUInt16           *v_uint16);
    IMBool      (*get_int32)                (IMStream           *stream,
                                             IMInt32            *v_int32);
    IMBool      (*get_uint32)               (IMStream           *stream,
                                             IMUInt32           *v_uint32);
    IMBool      (*get_int64)                (IMStream           *stream,
                                             IMInt64            *v_int64);
    IMBool      (*get_uint64)               (IMStream           *stream,
                                             IMUInt64           *v_uint64);
    IMBool      (*get_double)               (IMStream           *stream,
                                             IMDouble           *v_double);
    IMBool      (*get_c_string)             (IMStream           *stream,
                                             IMChar             *v_string,
                                             IMSize              v_strlen);
    IMBool      (*get_byte_array)           (IMStream           *stream,
                                             IMPointer           v_array,
                                             IMSize              v_size);
    IMBool      (*get_bool_array)           (IMStream           *stream,
                                             IMBool             *v_array,
                                             IMSize              v_size);
    IMBool      (*get_int16_array)          (IMStream           *stream,
                                             IMInt16            *v_array,
                                             IMSize              v_size);
    IMBool      (*get_uint16_array)         (IMStream           *stream,
                                             IMUInt16           *v_array,
                                             IMSize              v_size);
    IMBool      (*get_int32_array)          (IMStream           *stream,
                                             IMInt32            *v_array,
                                             IMSize              v_size);
    IMBool      (*get_uint32_array)         (IMStream           *stream,
                                             IMUInt32           *v_array,
                                             IMSize              v_size);
    IMBool      (*get_int64_array)          (IMStream           *stream,
                                             IMInt64            *v_array,
                                             IMSize              v_size);
    IMBool      (*get_uint64_array)         (IMStream           *stream,
                                             IMUInt64           *v_array,
                                             IMSize              v_size);
    IMBool      (*get_double_array)         (IMStream           *stream,
                                             IMDouble           *v_array,
                                             IMSize              v_size);
    IMBool      (*get_object)               (IMStream           *stream,
                                             IMPointer           v_object);
    IMBool      (*skip_data)                (IMStream           *stream);
    IMBool      (*rewind)                   (IMStream           *stream);

    IMBool      (*read)                     (IMStream           *stream,
                                             IMIOChannel        *channel,
                                             IMInt              *timeout,
                                             IMIOError          *error);
    IMBool      (*write)                    (IMStream           *stream,
                                             IMIOChannel        *channel,
                                             IMInt              *timeout,
                                             IMIOError          *error);
    IMSize      (*size)                     (IMStream           *stream);
};

/**
 * @brief Create a new IMStream object.
 *
 * As IMStream itself is a pure virtual class,
 * creating an object for IMStream class is not allowed.
 *
 * This function creates an object for a derived class of IMStream.
 *
 * @param type A class type which is derived from IMStream.
 */
IMStream*       im_stream_new               (IMType type);

/**
 * @brief Put a void (placeholder) into a stream.
 */
IMBool          im_stream_put_void          (IMStream           *stream);

/**
 * @brief Put a char into a stream.
 */
IMBool          im_stream_put_char          (IMStream           *stream,
                                             IMChar              v_char);
/**
 * @brief Put an unsigned char into a stream.
 */
IMBool          im_stream_put_uchar         (IMStream           *stream,
                                             IMUChar             v_uchar);
/**
 * @brief Put a boolean into a stream.
 */
IMBool          im_stream_put_bool          (IMStream           *stream,
                                             IMBool              v_bool);

/**
 * @brief Put a 16bit integer into a stream.
 */
IMBool          im_stream_put_int16         (IMStream           *stream,
                                             IMInt16             v_int16);

/**
 * @brief Put a 16bit unsigned integer into a stream.
 */
IMBool          im_stream_put_uint16        (IMStream           *stream,
                                             IMUInt16            v_uint16);

/**
 * @brief Put a 32bit integer into a stream.
 */
IMBool          im_stream_put_int32         (IMStream           *stream,
                                             IMInt32             v_int32);

/**
 * @brief Put a 32bit unsigned integer into a stream.
 */
IMBool          im_stream_put_uint32        (IMStream           *stream,
                                             IMUInt32            v_uint32);

/**
 * @brief Put a 64bit integer into a stream.
 */
IMBool          im_stream_put_int64         (IMStream           *stream,
                                             IMInt64             v_int64);

/**
 * @brief Put a 64bit unsigned integer into a stream.
 */
IMBool          im_stream_put_uint64        (IMStream           *stream,
                                             IMUInt64            v_uint64);

/**
 * @brief Put a double into a stream.
 */
IMBool          im_stream_put_double        (IMStream           *stream,
                                             IMDouble            v_double);

/**
 * @brief Put a null terminated char string into a stream.
 *
 * @param v_string A null terminated char string.
 * @param v_length Only copies at most v_length chars,
 *        not including the terminating '\0' character.
 *        -1 means unlimited until the end of string.
 */
IMBool          im_stream_put_c_string      (IMStream           *stream,
                                             const IMChar       *v_string,
                                             IMSize              v_length);

/**
 * @brief Put a byte array into a stream.
 *
 * @param v_array Pointer to the byte array.
 * @param v_size  Number of bytes in the array.
 */
IMBool          im_stream_put_byte_array    (IMStream           *stream,
                                             const IMPointer     v_array,
                                             IMSize              v_size);

/**
 * @brief Put a bool array into a stream.
 *
 * @param v_array Pointer to the bool array.
 * @param v_size  Number of IMBool elements in the array.
 */
IMBool          im_stream_put_bool_array    (IMStream           *stream,
                                             const IMBool       *v_array,
                                             IMSize              v_size);

/**
 * @brief Put an int16 array into a stream.
 *
 * @param v_array Pointer to the int16 array.
 * @param v_size  Number of IMInt16 elements in the array.
 */
IMBool          im_stream_put_int16_array   (IMStream           *stream,
                                             const IMInt16      *v_array,
                                             IMSize              v_size);

/**
 * @brief Put an uint16 array into a stream.
 *
 * @param v_array Pointer to the uint16 array.
 * @param v_size  Number of IMUInt16 elements in the array.
 */
IMBool          im_stream_put_uint16_array  (IMStream           *stream,
                                             const IMUInt16     *v_array,
                                             IMSize              v_size);

/**
 * @brief Put an int32 array into a stream.
 *
 * @param v_array Pointer to the int32 array.
 * @param v_size  Number of IMInt32 elements in the array.
 */
IMBool          im_stream_put_int32_array   (IMStream           *stream,
                                             const IMInt32      *v_array,
                                             IMSize              v_size);

/**
 * @brief Put an uint32 array into a stream.
 *
 * @param v_array Pointer to the uint32 array.
 * @param v_size  Number of IMUInt32 elements in the array.
 */
IMBool          im_stream_put_uint32_array  (IMStream           *stream,
                                             const IMUInt32     *v_array,
                                             IMSize              v_size);

/**
 * @brief Put an int64 array into a stream.
 *
 * @param v_array Pointer to the int64 array.
 * @param v_size  Number of IMInt64 elements in the array.
 */
IMBool          im_stream_put_int64_array   (IMStream           *stream,
                                             const IMInt64      *v_array,
                                             IMSize              v_size);

/**
 * @brief Put an uint64 array into a stream.
 *
 * @param v_array Pointer to the uint64 array.
 * @param v_size  Number of IMUInt64 elements in the array.
 */
IMBool          im_stream_put_uint64_array  (IMStream           *stream,
                                             const IMUInt64     *v_array,
                                             IMSize              v_size);

/**
 * @brief Put a double array into a stream.
 *
 * @param v_array Pointer to the double array.
 * @param v_size  Number of IMDouble elements in the array.
 */
IMBool          im_stream_put_double_array  (IMStream           *stream,
                                             const IMDouble     *v_array,
                                             IMSize              v_size);

/**
 * @brief Put an object into a stream.
 */
IMBool          im_stream_put_object        (IMStream           *stream,
                                             IMConstPointer      v_object);

/**
 * @brief Clear a stream. All data in the stream will be cleared.
 *
 * Some kinds of stream can not be cleared, such as the stream that
 * write data directly into a socket or pipe.
 */
void            im_stream_clear             (IMStream           *stream);

/**
 * @brief Get type of the data at current read position in a stream.
 */
IMType          im_stream_get_data_type     (IMStream           *stream);

/**
 * @brief Get size of the data at current read position in a stream.
 *
 * For string, returns string length not including the terminating '\0' character.
 * For array, return the number of elements in the array.
 * For fundamental data type, such as int32, double, return the real element size.
 * For object, returns the size of an object instance.
 */
IMSize          im_stream_get_data_size     (IMStream           *stream);

/**
 * @brief Get a void (placeholder) from a stream.
 *
 * @return TRUE if a void is successfully got.
 */
IMBool          im_stream_get_void          (IMStream           *stream);
/**
 * @brief Get a char from a stream.
 *
 * @return TRUE if a char is successfully got.
 */
IMBool          im_stream_get_char          (IMStream           *stream,
                                             IMChar             *v_char);
/**
 * @brief Get an unsigned char from a stream.
 *
 * @return TRUE if an unsigned char is successfully got.
 */
IMBool          im_stream_get_uchar         (IMStream           *stream,
                                             IMUChar            *v_uchar);

/**
 * @brief Get a boolean from a stream.
 *
 * @return TRUE if a boolean is successfully got.
 */
IMBool          im_stream_get_bool          (IMStream           *stream,
                                             IMBool             *v_bool);

/**
 * @brief Get a 16bit integer from a stream.
 *
 * @return TRUE if a 16bit integer is successfully got.
 */
IMBool          im_stream_get_int16         (IMStream           *stream,
                                             IMInt16            *v_int16);

/**
 * @brief Get a 16bit unsigned integer from a stream.
 *
 * @return TRUE if a 16bit unsigned integer is successfully got.
 */
IMBool          im_stream_get_uint16        (IMStream           *stream,
                                             IMUInt16           *v_uint16);

/**
 * @brief Get a 32bit integer from a stream.
 *
 * @return TRUE if a 32bit integer is successfully got.
 */
IMBool          im_stream_get_int32         (IMStream           *stream,
                                             IMInt32            *v_int32);

/**
 * @brief Get a 32bit unsigned integer from a stream.
 *
 * @return TRUE if a 32bit unsigned integer is successfully got.
 */
IMBool          im_stream_get_uint32        (IMStream           *stream,
                                             IMUInt32           *v_uint32);

/**
 * @brief Get a 64bit integer from a stream.
 *
 * @return TRUE if a 64bit integer is successfully got.
 */
IMBool          im_stream_get_int64         (IMStream           *stream,
                                             IMInt64            *v_int64);

/**
 * @brief Get a 64bit unsigned integer from a stream.
 *
 * @return TRUE if a 64bit unsigned integer is successfully got.
 */
IMBool          im_stream_get_uint64        (IMStream           *stream,
                                             IMUInt64           *v_uint64);

/**
 * @brief Get a double from a stream.
 *
 * @return TRUE if a double is successfully got.
 */
IMBool          im_stream_get_double        (IMStream           *stream,
                                             IMDouble           *v_double);

/**
 * @brief Get a string from a stream.
 *
 * @param v_string A buffer to hold the string.
 * @param v_length How many characters will be copied at most.
 *        Thus if there is no null byte among the first
 *        v_length bytes, the result will not be null-terminated.
 *        If the string length is less than v_length, it'll be
 *        terminated with null.
 * @return TRUE if a string is successfully got.
 */
IMBool          im_stream_get_c_string      (IMStream           *stream,
                                             IMChar             *v_string,
                                             IMSize              v_length);

/**
 * @brief Get a byte array from a stream.
 *
 * @param v_array A byte array to store the result.
 * @param v_size  Number of bytes can be stored in the array.
 *
 * @return TRUE if successful.
 */
IMBool          im_stream_get_byte_array    (IMStream           *stream,
                                             IMPointer           v_array,
                                             IMSize              v_size);

/**
 * @brief Get a bool array from a stream.
 *
 * @param v_array A bool array to store the result.
 * @param v_size  Number of IMBool elements can be stored in the array.
 *
 * @return TRUE if successful.
 */
IMBool          im_stream_get_bool_array    (IMStream           *stream,
                                             IMBool             *v_array,
                                             IMSize              v_size);

/**
 * @brief Get an int16 array from a stream.
 *
 * @param v_array An int16 array to store the result.
 * @param v_size  Number of IMInt16 elements can be stored in the array.
 *
 * @return TRUE if successful.
 */
IMBool          im_stream_get_int16_array   (IMStream           *stream,
                                             IMInt16            *v_array,
                                             IMSize              v_size);

/**
 * @brief Get an uint16 array from a stream.
 *
 * @param v_array An uint16 array to store the result.
 * @param v_size  Number of IMUInt16 elements can be stored in the array.
 *
 * @return TRUE if successful.
 */
IMBool          im_stream_get_uint16_array  (IMStream           *stream,
                                             IMUInt16           *v_array,
                                             IMSize              v_size);

/**
 * @brief Get an int32 array from a stream.
 *
 * @param v_array An int32 array to store the result.
 * @param v_size  Number of IMInt32 elements can be stored in the array.
 *
 * @return TRUE if successful.
 */
IMBool          im_stream_get_int32_array   (IMStream           *stream,
                                             IMInt32            *v_array,
                                             IMSize              v_size);

/**
 * @brief Get an uint32 array from a stream.
 *
 * @param v_array An uint32 array to store the result.
 * @param v_size  Number of IMUInt32 elements can be stored in the array.
 *
 * @return TRUE if successful.
 */
IMBool          im_stream_get_uint32_array  (IMStream           *stream,
                                             IMUInt32           *v_array,
                                             IMSize              v_size);

/**
 * @brief Get an int64 array from a stream.
 *
 * @param v_array An int64 array to store the result.
 * @param v_size  Number of IMInt64 elements can be stored in the array.
 *
 * @return TRUE if successful.
 */
IMBool          im_stream_get_int64_array   (IMStream           *stream,
                                             IMInt64            *v_array,
                                             IMSize              v_size);

/**
 * @brief Get an uint64 array from a stream.
 *
 * @param v_array An uint64 array to store the result.
 * @param v_size  Number of IMUInt64 elements can be stored in the array.
 *
 * @return TRUE if successful.
 */
IMBool          im_stream_get_uint64_array  (IMStream           *stream,
                                             IMUInt64           *v_array,
                                             IMSize              v_size);

/**
 * @brief Get a double array from a stream.
 *
 * @param v_array A double array to store the result.
 * @param v_size  Number of IMDouble elements can be stored in the array.
 *
 * @return TRUE if successful.
 */
IMBool          im_stream_get_double_array  (IMStream           *stream,
                                             IMDouble           *v_array,
                                             IMSize              v_size);

/**
 * @brief Get an object from a stream.
 *
 * @return TRUE if an object is successfully got.
 */
IMBool          im_stream_get_object        (IMStream           *stream,
                                             IMPointer           v_object);

/**
 * @brief Skip a datum at current read position in a stream.
 *
 * @return TRUE if a datum is successfully skipped.
 */
IMBool          im_stream_skip_data         (IMStream           *stream);

/**
 * @brief Rewind a stream, so that the data can be read again.
 *
 * Not all streams can be rewinded.
 *
 * @return TRUE if the stream is successfully rewinded.
 */
IMBool          im_stream_rewind            (IMStream           *stream);

/**
 * @brief Read a stream's data from a IMIOChannel object.
 *
 * @param stream the IMStream object which data will be read.
 * @param channel the IMIOChannel object from which data will be read.
 * @param timeout the maxmium wait time when reading data. In milliseconds.
 *                if it's NULL or the value is 0, means don't wait.
 *                if its value is -1, means wait forever until the required
 *                data are read.
 * @return TRUE if the stream is successfully read, otherwise the error
 *         number will be returned in error.
 */
IMBool          im_stream_read              (IMStream           *stream,
                                             IMIOChannel        *channel,
                                             IMInt              *timeout,
                                             IMIOError          *error);

/**
 * @brief Write a stream's data to a IMIOChannel object.
 *
 * @param stream the IMStream object which data will be read.
 * @param channel the IMIOChannel object from which data will be read.
 * @param timeout the maxmium wait time when reading data. In milliseconds.
 *                if it's NULL or the value is 0, means don't wait.
 *                if its value is -1, means wait forever until the required
 *                data are read.
 * @return TRUE if the stream is successfully written, otherwise the error
 *         number will be returned in error.
 */
IMBool          im_stream_write             (IMStream           *stream,
                                             IMIOChannel        *channel,
                                             IMInt              *timeout,
                                             IMIOError          *error);

/**
 * @brief Return the size of a specified stream, in number of bytes.
 */
IMSize          im_stream_size              (IMStream           *stream);

IM_END_DECLS
/** @} */

#endif
/*
vi:ts=4:nowrap:ai:expandtab
*/
